// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;

namespace System.Net.Mime
{
    /// <summary>
    /// Provides methods for mapping between file extensions and media types (MIME types).
    /// </summary>
    public static class MediaTypeMap
    {
        private const int ExtensionToMediaTypeCount = 403;
        private const int MediaTypeToExtensionCount = 294;
        private const int MaxExtensionLength = 12; // Length of longest extension including the dot

        private static readonly Dictionary<string, string>.AlternateLookup<ReadOnlySpan<char>> s_extensionToMediaType = new Dictionary<string, string>(ExtensionToMediaTypeCount, StringComparer.OrdinalIgnoreCase)
        {
            [".3g2"] = "video/3gpp2",
            [".3gp"] = "video/3gpp",
            [".3gp2"] = "video/3gpp2",
            [".3gpp"] = "video/3gpp",
            [".7z"] = "application/x-7z-compressed",
            [".aac"] = "audio/aac",
            [".abw"] = "application/x-abiword",
            [".accdb"] = "application/msaccess",
            [".accde"] = "application/msaccess",
            [".accdt"] = "application/msaccess",
            [".adt"] = "audio/vnd.dlna.adts",
            [".adts"] = "audio/vnd.dlna.adts",
            [".ai"] = "application/postscript",
            [".aif"] = "audio/x-aiff",
            [".aifc"] = "audio/aifc",
            [".aiff"] = "audio/aiff",
            [".apk"] = "application/vnd.android.package-archive",
            [".apng"] = "image/apng",
            [".appcache"] = "text/cache-manifest",
            [".application"] = "application/x-ms-application",
            [".arc"] = "application/x-freearc",
            [".asf"] = "video/x-ms-asf",
            [".asm"] = "text/plain",
            [".asr"] = "video/x-ms-asf",
            [".asx"] = "video/x-ms-asf",
            [".atom"] = "application/atom+xml",
            [".au"] = "audio/basic",
            [".avi"] = "video/x-msvideo",
            [".avif"] = "image/avif",
            [".azw"] = "application/vnd.amazon.ebook",
            [".bas"] = "text/plain",
            [".bcpio"] = "application/x-bcpio",
            [".bmp"] = "image/bmp",
            [".br"] = "application/brotli",
            [".bz"] = "application/x-bzip",
            [".bz2"] = "application/x-bzip2",
            [".c"] = "text/plain",
            [".cab"] = "application/vnd.ms-cab-compressed",
            [".calx"] = "application/vnd.ms-office.calx",
            [".cat"] = "application/vnd.ms-pki.seccat",
            [".cbor"] = "application/cbor",
            [".cdf"] = "application/x-cdf",
            [".cer"] = "application/x-x509-ca-cert",
            [".cjs"] = "text/javascript",
            [".class"] = "application/java-vm",
            [".clp"] = "application/x-msclip",
            [".cmx"] = "image/x-cmx",
            [".cnf"] = "text/plain",
            [".config"] = "text/plain",
            [".cpio"] = "application/x-cpio",
            [".cpp"] = "text/plain",
            [".crd"] = "application/x-mscardfile",
            [".crl"] = "application/pkix-crl",
            [".crt"] = "application/x-x509-ca-cert",
            [".cs"] = "text/x-csharp",
            [".csproj"] = "text/xml",
            [".csh"] = "application/x-csh",
            [".css"] = "text/css",
            [".csv"] = "text/csv",
            [".cue"] = "application/x-cue",
            [".cts"] = "text/typescript",
            [".dart"] = "text/x-dart",
            [".db"] = "application/x-sqlite3",
            [".dbf"] = "application/x-dbf",
            [".deb"] = "application/vnd.debian.binary-package",
            [".dcr"] = "application/x-director",
            [".der"] = "application/x-x509-ca-cert",
            [".dib"] = "image/bmp",
            [".dir"] = "application/x-director",
            [".disco"] = "text/xml",
            [".dmg"] = "application/x-apple-diskimage",
            [".doc"] = "application/msword",
            [".docm"] = "application/vnd.ms-word.document.macroEnabled.12",
            [".docx"] = "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
            [".dot"] = "application/msword",
            [".dotm"] = "application/vnd.ms-word.template.macroEnabled.12",
            [".dotx"] = "application/vnd.openxmlformats-officedocument.wordprocessingml.template",
            [".dtd"] = "application/xml-dtd",
            [".dvi"] = "application/x-dvi",
            [".dvr-ms"] = "video/x-ms-dvr",
            [".dwf"] = "drawing/x-dwf",
            [".dxr"] = "application/x-director",
            [".eml"] = "message/rfc822",
            [".eot"] = "application/vnd.ms-fontobject",
            [".eps"] = "application/postscript",
            [".epub"] = "application/epub+zip",
            [".etx"] = "text/x-setext",
            [".fdf"] = "application/vnd.fdf",
            [".flac"] = "audio/flac",
            [".flv"] = "video/x-flv",
            [".geojson"] = "application/geo+json",
            [".gif"] = "image/gif",
            [".glb"] = "model/gltf-binary",
            [".gltf"] = "model/gltf+json",
            [".go"] = "text/x-go",
            [".gpx"] = "application/gpx+xml",
            [".graphql"] = "application/graphql",
            [".gtar"] = "application/x-gtar",
            [".gz"] = "application/gzip",
            [".h"] = "text/plain",
            [".hdf"] = "application/x-hdf",
            [".heic"] = "image/heic",
            [".heif"] = "image/heif",
            [".hhc"] = "application/x-oleobject",
            [".hlp"] = "application/winhlp",
            [".hqx"] = "application/mac-binhex40",
            [".hta"] = "application/hta",
            [".htc"] = "text/x-component",
            [".htm"] = "text/html",
            [".html"] = "text/html",
            [".hwp"] = "application/x-hwp",
            [".ical"] = "text/calendar",
            [".icalendar"] = "text/calendar",
            [".ico"] = "image/vnd.microsoft.icon",
            [".ics"] = "text/calendar",
            [".ief"] = "image/ief",
            [".ifb"] = "text/calendar",
            [".ini"] = "text/plain",
            [".ins"] = "application/x-internet-signup",
            [".iso"] = "application/x-iso9660-image",
            [".isp"] = "application/x-internet-signup",
            [".ivf"] = "video/x-ivf",
            [".jar"] = "application/java-archive",
            [".java"] = "text/x-java-source",
            [".jfif"] = "image/jpeg",
            [".jpe"] = "image/jpeg",
            [".jpeg"] = "image/jpeg",
            [".jpg"] = "image/jpeg",
            [".js"] = "text/javascript",
            [".json"] = "application/json",
            [".jsonld"] = "application/ld+json",
            [".jsonl"] = "application/x-ndjson",
            [".jsx"] = "text/jsx",
            [".jxl"] = "image/jxl",
            [".kt"] = "text/x-kotlin",
            [".kts"] = "text/x-kotlin",
            [".key"] = "application/vnd.apple.keynote",
            [".kml"] = "application/vnd.google-earth.kml+xml",
            [".kmz"] = "application/vnd.google-earth.kmz",
            [".latex"] = "application/x-latex",
            [".less"] = "text/x-less",
            [".lit"] = "application/x-ms-reader",
            [".log"] = "text/plain",
            [".lsf"] = "video/x-la-asf",
            [".lwp"] = "application/vnd.lotus-wordpro",
            [".lsx"] = "video/x-la-asf",
            [".m13"] = "application/x-msmediaview",
            [".m14"] = "application/x-msmediaview",
            [".m1v"] = "video/mpeg",
            [".m2t"] = "video/vnd.dlna.mpeg-tts",
            [".m2ts"] = "video/vnd.dlna.mpeg-tts",
            [".m3u"] = "audio/x-mpegurl",
            [".m3u8"] = "application/vnd.apple.mpegurl",
            [".m4a"] = "audio/mp4",
            [".m4v"] = "video/mp4",
            [".man"] = "application/x-troff-man",
            [".manifest"] = "application/x-ms-manifest",
            [".markdown"] = "text/markdown",
            [".md"] = "text/markdown",
            [".mdb"] = "application/x-msaccess",
            [".mdx"] = "text/mdx",
            [".me"] = "application/x-troff-me",
            [".mht"] = "message/rfc822",
            [".mhtml"] = "message/rfc822",
            [".mid"] = "audio/midi",
            [".midi"] = "audio/midi",
            [".mjs"] = "text/javascript",
            [".mka"] = "audio/x-matroska",
            [".mkv"] = "video/x-matroska",
            [".mmf"] = "application/x-smaf",
            [".mno"] = "text/xml",
            [".mny"] = "application/x-msmoney",
            [".mov"] = "video/quicktime",
            [".movie"] = "video/x-sgi-movie",
            [".mp2"] = "video/mpeg",
            [".mp3"] = "audio/mpeg",
            [".mp4"] = "video/mp4",
            [".mp4v"] = "video/mp4",
            [".mpa"] = "video/mpeg",
            [".mpd"] = "application/dash+xml",
            [".mpe"] = "video/mpeg",
            [".mpeg"] = "video/mpeg",
            [".mpg"] = "video/mpeg",
            [".mpkg"] = "application/vnd.apple.installer+xml",
            [".mpp"] = "application/vnd.ms-project",
            [".mpv2"] = "video/mpeg",
            [".mts"] = "video/mp2t",
            [".mvb"] = "application/x-msmediaview",
            [".mvc"] = "application/x-miva-compiled",
            [".nc"] = "application/x-netcdf",
            [".nsc"] = "video/x-ms-asf",
            [".ndjson"] = "application/x-ndjson",
            [".numbers"] = "application/vnd.apple.numbers",
            [".nupkg"] = "application/zip",
            [".nws"] = "message/rfc822",
            [".oda"] = "application/oda",
            [".odc"] = "text/x-ms-odc",
            [".odf"] = "application/vnd.oasis.opendocument.formula",
            [".odg"] = "application/vnd.oasis.opendocument.graphics",
            [".odp"] = "application/vnd.oasis.opendocument.presentation",
            [".ods"] = "application/vnd.oasis.opendocument.spreadsheet",
            [".odt"] = "application/vnd.oasis.opendocument.text",
            [".oga"] = "audio/ogg",
            [".ogg"] = "audio/ogg",
            [".ogv"] = "video/ogg",
            [".ogx"] = "application/ogg",
            [".one"] = "application/onenote",
            [".onea"] = "application/onenote",
            [".onepkg"] = "application/onenote",
            [".onetmp"] = "application/onenote",
            [".onetoc"] = "application/onenote",
            [".onetoc2"] = "application/onenote",
            [".opus"] = "audio/opus",
            [".osdx"] = "application/opensearchdescription+xml",
            [".otf"] = "font/otf",
            [".pages"] = "application/vnd.apple.pages",
            [".parquet"] = "application/vnd.apache.parquet",
            [".p10"] = "application/pkcs10",
            [".p12"] = "application/x-pkcs12",
            [".p7b"] = "application/x-pkcs7-certificates",
            [".p7c"] = "application/pkcs7-mime",
            [".p7m"] = "application/pkcs7-mime",
            [".p7r"] = "application/x-pkcs7-certreqresp",
            [".p7s"] = "application/pkcs7-signature",
            [".pbm"] = "image/x-portable-bitmap",
            [".pdf"] = "application/pdf",
            [".pem"] = "application/x-pem-file",
            [".pfx"] = "application/x-pkcs12",
            [".pgm"] = "image/x-portable-graymap",
            [".php"] = "application/x-httpd-php",
            [".pko"] = "application/vnd.ms-pki.pko",
            [".pl"] = "text/x-perl",
            [".pm"] = "text/x-perl",
            [".pma"] = "application/x-perfmon",
            [".pmc"] = "application/x-perfmon",
            [".pml"] = "application/x-perfmon",
            [".pmr"] = "application/x-perfmon",
            [".pmw"] = "application/x-perfmon",
            [".png"] = "image/png",
            [".pnm"] = "image/x-portable-anymap",
            [".pnz"] = "image/png",
            [".pot"] = "application/vnd.ms-powerpoint",
            [".potm"] = "application/vnd.ms-powerpoint.template.macroEnabled.12",
            [".potx"] = "application/vnd.openxmlformats-officedocument.presentationml.template",
            [".ppam"] = "application/vnd.ms-powerpoint.addin.macroEnabled.12",
            [".ppm"] = "image/x-portable-pixmap",
            [".pps"] = "application/vnd.ms-powerpoint",
            [".ppsm"] = "application/vnd.ms-powerpoint.slideshow.macroEnabled.12",
            [".ppsx"] = "application/vnd.openxmlformats-officedocument.presentationml.slideshow",
            [".ppt"] = "application/vnd.ms-powerpoint",
            [".pptm"] = "application/vnd.ms-powerpoint.presentation.macroEnabled.12",
            [".pptx"] = "application/vnd.openxmlformats-officedocument.presentationml.presentation",
            [".proto"] = "text/x-protobuf",
            [".ps"] = "application/postscript",
            [".ps1"] = "application/powershell",
            [".pub"] = "application/x-mspublisher",
            [".py"] = "text/x-python",
            [".pyi"] = "text/x-python",
            [".pyw"] = "text/x-python",
            [".qt"] = "video/quicktime",
            [".qtl"] = "application/x-quicktimeplayer",
            [".rar"] = "application/vnd.rar",
            [".ras"] = "image/x-cmu-raster",
            [".rgb"] = "image/x-rgb",
            [".rmi"] = "audio/mid",
            [".roff"] = "application/x-troff",
            [".rpm"] = "application/x-rpm",
            [".rs"] = "text/x-rust",
            [".rss"] = "application/rss+xml",
            [".rtf"] = "application/rtf",
            [".rtx"] = "text/richtext",
            [".sass"] = "text/x-sass",
            [".scd"] = "application/x-msschedule",
            [".scss"] = "text/x-scss",
            [".sct"] = "text/scriptlet",
            [".sda"] = "application/vnd.stardivision.draw",
            [".sdd"] = "application/vnd.stardivision.impress",
            [".sdw"] = "application/vnd.stardivision.writer",
            [".setpay"] = "application/set-payment-initiation",
            [".setreg"] = "application/set-registration-initiation",
            [".sgml"] = "text/sgml",
            [".sh"] = "application/x-sh",
            [".shar"] = "application/x-shar",
            [".sit"] = "application/x-stuffit",
            [".slk"] = "text/vnd.sylk",
            [".sln"] = "text/plain",
            [".sldm"] = "application/vnd.ms-powerpoint.slide.macroEnabled.12",
            [".sldx"] = "application/vnd.openxmlformats-officedocument.presentationml.slide",
            [".snd"] = "audio/basic",
            [".snupkg"] = "application/zip",
            [".spc"] = "application/x-pkcs7-certificates",
            [".spx"] = "audio/ogg",
            [".sql"] = "application/sql",
            [".sqlite"] = "application/x-sqlite3",
            [".sqlite3"] = "application/x-sqlite3",
            [".src"] = "application/x-wais-source",
            [".sst"] = "application/vnd.ms-pki.certstore",
            [".sti"] = "application/vnd.sun.xml.impress.template",
            [".stl"] = "model/stl",
            [".stw"] = "application/vnd.sun.xml.writer.template",
            [".sv4cpio"] = "application/x-sv4cpio",
            [".sv4crc"] = "application/x-sv4crc",
            [".svelte"] = "text/svelte",
            [".svg"] = "image/svg+xml",
            [".svgz"] = "image/svg+xml",
            [".sxg"] = "application/vnd.sun.xml.writer.global",
            [".sxi"] = "application/vnd.sun.xml.impress",
            [".sxw"] = "application/vnd.sun.xml.writer",
            [".swf"] = "application/x-shockwave-flash",
            [".sylk"] = "text/vnd.sylk",
            [".swift"] = "text/x-swift",
            [".tar"] = "application/x-tar",
            [".tcl"] = "application/x-tcl",
            [".tex"] = "application/x-tex",
            [".texi"] = "application/x-texinfo",
            [".texinfo"] = "application/x-texinfo",
            [".tgz"] = "application/x-compressed",
            [".thmx"] = "application/vnd.ms-officetheme",
            [".tif"] = "image/tiff",
            [".tiff"] = "image/tiff",
            [".toml"] = "application/toml",
            [".tr"] = "application/x-troff",
            [".trm"] = "application/x-msterminal",
            [".ts"] = "text/typescript",
            [".tsv"] = "text/tab-separated-values",
            [".tsx"] = "text/tsx",
            [".ttc"] = "font/collection",
            [".ttf"] = "font/ttf",
            [".tts"] = "video/vnd.dlna.mpeg-tts",
            [".txt"] = "text/plain",
            [".ustar"] = "application/x-ustar",
            [".vbs"] = "text/vbscript",
            [".vcf"] = "text/vcard",
            [".vcs"] = "text/x-vcalendar",
            [".vdx"] = "application/vnd.ms-visio.viewer",
            [".vml"] = "text/xml",
            [".vsd"] = "application/vnd.visio",
            [".vss"] = "application/vnd.visio",
            [".vst"] = "application/vnd.visio",
            [".vsto"] = "application/x-ms-vsto",
            [".vsw"] = "application/vnd.visio",
            [".vsx"] = "application/vnd.visio",
            [".vtt"] = "text/vtt",
            [".vtx"] = "application/vnd.visio",
            [".vue"] = "text/vue",
            [".wasm"] = "application/wasm",
            [".wav"] = "audio/wav",
            [".wax"] = "audio/x-ms-wax",
            [".wbmp"] = "image/vnd.wap.wbmp",
            [".wcm"] = "application/vnd.ms-works",
            [".wdb"] = "application/vnd.ms-works",
            [".weba"] = "audio/webm",
            [".webm"] = "video/webm",
            [".webmanifest"] = "application/manifest+json",
            [".webp"] = "image/webp",
            [".wks"] = "application/vnd.ms-works",
            [".wm"] = "video/x-ms-wm",
            [".wma"] = "audio/x-ms-wma",
            [".wmd"] = "application/x-ms-wmd",
            [".wmf"] = "application/x-msmetafile",
            [".wmp"] = "video/x-ms-wmp",
            [".wmv"] = "video/x-ms-wmv",
            [".wmx"] = "video/x-ms-wmx",
            [".wmz"] = "application/x-ms-wmz",
            [".woff"] = "font/woff",
            [".woff2"] = "font/woff2",
            [".wpd"] = "application/vnd.wordperfect",
            [".wps"] = "application/vnd.ms-works",
            [".wri"] = "application/x-mswrite",
            [".wsdl"] = "text/xml",
            [".wtv"] = "video/x-ms-wtv",
            [".wvx"] = "video/x-ms-wvx",
            [".xaml"] = "application/xaml+xml",
            [".xbm"] = "image/x-xbitmap",
            [".xdr"] = "text/plain",
            [".xht"] = "application/xhtml+xml",
            [".xhtml"] = "application/xhtml+xml",
            [".xla"] = "application/vnd.ms-excel",
            [".xlam"] = "application/vnd.ms-excel.addin.macroEnabled.12",
            [".xlc"] = "application/vnd.ms-excel",
            [".xlm"] = "application/vnd.ms-excel",
            [".xls"] = "application/vnd.ms-excel",
            [".xlsb"] = "application/vnd.ms-excel.sheet.binary.macroEnabled.12",
            [".xlsm"] = "application/vnd.ms-excel.sheet.macroEnabled.12",
            [".xlsx"] = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
            [".xlt"] = "application/vnd.ms-excel",
            [".xltm"] = "application/vnd.ms-excel.template.macroEnabled.12",
            [".xltx"] = "application/vnd.openxmlformats-officedocument.spreadsheetml.template",
            [".xlw"] = "application/vnd.ms-excel",
            [".xml"] = "application/xml",
            [".xpm"] = "image/x-xpixmap",
            [".xps"] = "application/vnd.ms-xpsdocument",
            [".xsd"] = "text/xml",
            [".xsf"] = "text/xml",
            [".xsl"] = "text/xml",
            [".xslt"] = "text/xml",
            [".xul"] = "application/vnd.mozilla.xul+xml",
            [".xwd"] = "image/x-xwindowdump",
            [".yaml"] = "application/yaml",
            [".yml"] = "application/yaml",
            [".z"] = "application/x-compress",
            [".zip"] = "application/zip",
            [".zst"] = "application/zstd",
        }.GetAlternateLookup<ReadOnlySpan<char>>();

        private static readonly Dictionary<string, string>.AlternateLookup<ReadOnlySpan<char>> s_mediaTypeToExtension = new Dictionary<string, string>(MediaTypeToExtensionCount, StringComparer.OrdinalIgnoreCase)
        {
            ["application/atom+xml"] = ".atom",
            ["application/brotli"] = ".br",
            ["application/cbor"] = ".cbor",
            ["application/dash+xml"] = ".mpd",
            ["application/epub+zip"] = ".epub",
            ["application/geo+json"] = ".geojson",
            ["application/graphql"] = ".graphql",
            ["application/gpx+xml"] = ".gpx",
            ["application/gzip"] = ".gz",
            ["application/hta"] = ".hta",
            ["application/java-archive"] = ".jar",
            ["application/java-vm"] = ".class",
            ["application/json"] = ".json",
            ["application/ld+json"] = ".jsonld",
            ["application/mac-binhex40"] = ".hqx",
            ["application/manifest+json"] = ".webmanifest",
            ["application/msaccess"] = ".mdb",
            ["application/msword"] = ".doc",
            ["application/oda"] = ".oda",
            ["application/ogg"] = ".ogx",
            ["application/onenote"] = ".one",
            ["application/opensearchdescription+xml"] = ".osdx",
            ["application/pdf"] = ".pdf",
            ["application/pkcs10"] = ".p10",
            ["application/pkcs7-mime"] = ".p7c",
            ["application/pkcs7-signature"] = ".p7s",
            ["application/pkix-crl"] = ".crl",
            ["application/powershell"] = ".ps1",
            ["application/postscript"] = ".ps",
            ["application/rtf"] = ".rtf",
            ["application/rss+xml"] = ".rss",
            ["application/set-payment-initiation"] = ".setpay",
            ["application/set-registration-initiation"] = ".setreg",
            ["application/sql"] = ".sql",
            ["application/toml"] = ".toml",
            ["application/vnd.amazon.ebook"] = ".azw",
            ["application/vnd.android.package-archive"] = ".apk",
            ["application/vnd.apache.parquet"] = ".parquet",
            ["application/vnd.apple.installer+xml"] = ".mpkg",
            ["application/vnd.apple.keynote"] = ".key",
            ["application/vnd.apple.mpegurl"] = ".m3u8",
            ["application/vnd.apple.numbers"] = ".numbers",
            ["application/vnd.apple.pages"] = ".pages",
            ["application/vnd.debian.binary-package"] = ".deb",
            ["application/vnd.fdf"] = ".fdf",
            ["application/vnd.google-earth.kml+xml"] = ".kml",
            ["application/vnd.google-earth.kmz"] = ".kmz",
            ["application/vnd.lotus-wordpro"] = ".lwp",
            ["application/vnd.mozilla.xul+xml"] = ".xul",
            ["application/vnd.ms-cab-compressed"] = ".cab",
            ["application/vnd.ms-excel"] = ".xls",
            ["application/vnd.ms-excel.addin.macroEnabled.12"] = ".xlam",
            ["application/vnd.ms-excel.sheet.binary.macroEnabled.12"] = ".xlsb",
            ["application/vnd.ms-excel.sheet.macroEnabled.12"] = ".xlsm",
            ["application/vnd.ms-excel.template.macroEnabled.12"] = ".xltm",
            ["application/vnd.ms-fontobject"] = ".eot",
            ["application/vnd.ms-office.calx"] = ".calx",
            ["application/vnd.ms-officetheme"] = ".thmx",
            ["application/vnd.ms-pki.certstore"] = ".sst",
            ["application/vnd.ms-pki.pko"] = ".pko",
            ["application/vnd.ms-pki.seccat"] = ".cat",
            ["application/vnd.ms-powerpoint"] = ".ppt",
            ["application/vnd.ms-powerpoint.addin.macroEnabled.12"] = ".ppam",
            ["application/vnd.ms-powerpoint.presentation.macroEnabled.12"] = ".pptm",
            ["application/vnd.ms-powerpoint.slide.macroEnabled.12"] = ".sldm",
            ["application/vnd.ms-powerpoint.slideshow.macroEnabled.12"] = ".ppsm",
            ["application/vnd.ms-powerpoint.template.macroEnabled.12"] = ".potm",
            ["application/vnd.ms-project"] = ".mpp",
            ["application/vnd.ms-visio.viewer"] = ".vdx",
            ["application/vnd.ms-word.document.macroEnabled.12"] = ".docm",
            ["application/vnd.ms-word.template.macroEnabled.12"] = ".dotm",
            ["application/vnd.ms-works"] = ".wcm",
            ["application/vnd.ms-xpsdocument"] = ".xps",
            ["application/vnd.oasis.opendocument.formula"] = ".odf",
            ["application/vnd.oasis.opendocument.graphics"] = ".odg",
            ["application/vnd.oasis.opendocument.presentation"] = ".odp",
            ["application/vnd.oasis.opendocument.spreadsheet"] = ".ods",
            ["application/vnd.oasis.opendocument.text"] = ".odt",
            ["application/vnd.openxmlformats-officedocument.presentationml.presentation"] = ".pptx",
            ["application/vnd.openxmlformats-officedocument.presentationml.slide"] = ".sldx",
            ["application/vnd.openxmlformats-officedocument.presentationml.slideshow"] = ".ppsx",
            ["application/vnd.openxmlformats-officedocument.presentationml.template"] = ".potx",
            ["application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"] = ".xlsx",
            ["application/vnd.openxmlformats-officedocument.spreadsheetml.template"] = ".xltx",
            ["application/vnd.openxmlformats-officedocument.wordprocessingml.document"] = ".docx",
            ["application/vnd.openxmlformats-officedocument.wordprocessingml.template"] = ".dotx",
            ["application/vnd.rar"] = ".rar",
            ["application/vnd.stardivision.draw"] = ".sda",
            ["application/vnd.stardivision.impress"] = ".sdd",
            ["application/vnd.stardivision.writer"] = ".sdw",
            ["application/vnd.sun.xml.impress"] = ".sxi",
            ["application/vnd.sun.xml.impress.template"] = ".sti",
            ["application/vnd.sun.xml.writer"] = ".sxw",
            ["application/vnd.sun.xml.writer.global"] = ".sxg",
            ["application/vnd.sun.xml.writer.template"] = ".stw",
            ["application/vnd.visio"] = ".vsd",
            ["application/vnd.wordperfect"] = ".wpd",
            ["application/wasm"] = ".wasm",
            ["application/winhlp"] = ".hlp",
            ["application/x-7z-compressed"] = ".7z",
            ["application/x-abiword"] = ".abw",
            ["application/x-apple-diskimage"] = ".dmg",
            ["application/xaml+xml"] = ".xaml",
            ["application/x-bcpio"] = ".bcpio",
            ["application/x-dbf"] = ".dbf",
            ["application/x-brotli"] = ".br",
            ["application/x-bzip"] = ".bz",
            ["application/x-bzip2"] = ".bz2",
            ["application/x-cdf"] = ".cdf",
            ["application/x-compress"] = ".z",
            ["application/x-compressed"] = ".tgz",
            ["application/x-cpio"] = ".cpio",
            ["application/x-cue"] = ".cue",
            ["application/x-csh"] = ".csh",
            ["application/x-director"] = ".dcr",
            ["application/x-dvi"] = ".dvi",
            ["application/x-freearc"] = ".arc",
            ["application/x-gtar"] = ".gtar",
            ["application/x-hdf"] = ".hdf",
            ["application/x-hwp"] = ".hwp",
            ["application/x-iso9660-image"] = ".iso",
            ["application/xhtml+xml"] = ".xhtml",
            ["application/x-httpd-php"] = ".php",
            ["application/x-internet-signup"] = ".ins",
            ["application/x-latex"] = ".latex",
            ["application/x-miva-compiled"] = ".mvc",
            ["application/xml"] = ".xml",
            ["application/xml-dtd"] = ".dtd",
            ["application/x-msaccess"] = ".mdb",
            ["application/x-ms-application"] = ".application",
            ["application/x-mscardfile"] = ".crd",
            ["application/x-msclip"] = ".clp",
            ["application/x-ms-manifest"] = ".manifest",
            ["application/x-msmediaview"] = ".m13",
            ["application/x-msmetafile"] = ".wmf",
            ["application/x-msmoney"] = ".mny",
            ["application/x-mspublisher"] = ".pub",
            ["application/x-ms-reader"] = ".lit",
            ["application/x-msschedule"] = ".scd",
            ["application/x-msterminal"] = ".trm",
            ["application/x-ms-vsto"] = ".vsto",
            ["application/x-ms-wmd"] = ".wmd",
            ["application/x-ms-wmz"] = ".wmz",
            ["application/x-mswrite"] = ".wri",
            ["application/x-netcdf"] = ".nc",
            ["application/x-ndjson"] = ".jsonl",
            ["application/x-oleobject"] = ".hhc",
            ["application/x-perfmon"] = ".pma",
            ["application/x-pem-file"] = ".pem",
            ["application/x-pkcs12"] = ".p12",
            ["application/x-pkcs7-certificates"] = ".p7b",
            ["application/x-pkcs7-certreqresp"] = ".p7r",
            ["application/x-quicktimeplayer"] = ".qtl",
            ["application/x-rpm"] = ".rpm",
            ["application/x-sh"] = ".sh",
            ["application/x-shar"] = ".shar",
            ["application/x-shockwave-flash"] = ".swf",
            ["application/x-smaf"] = ".mmf",
            ["application/x-sqlite3"] = ".sqlite",
            ["application/x-stuffit"] = ".sit",
            ["application/x-sv4cpio"] = ".sv4cpio",
            ["application/x-sv4crc"] = ".sv4crc",
            ["application/x-tar"] = ".tar",
            ["application/x-tcl"] = ".tcl",
            ["application/x-tex"] = ".tex",
            ["application/x-texinfo"] = ".texi",
            ["application/x-troff"] = ".roff",
            ["application/x-troff-man"] = ".man",
            ["application/x-troff-me"] = ".me",
            ["application/x-ustar"] = ".ustar",
            ["application/x-wais-source"] = ".src",
            ["application/x-x509-ca-cert"] = ".crt",
            ["application/yaml"] = ".yaml",
            ["application/zip"] = ".zip",
            ["application/zstd"] = ".zst",
            ["audio/aac"] = ".aac",
            ["audio/aifc"] = ".aifc",
            ["audio/aiff"] = ".aiff",
            ["audio/basic"] = ".au",
            ["audio/flac"] = ".flac",
            ["audio/mid"] = ".mid",
            ["audio/midi"] = ".mid",
            ["audio/mp4"] = ".m4a",
            ["audio/mpeg"] = ".mp3",
            ["audio/ogg"] = ".oga",
            ["audio/opus"] = ".opus",
            ["audio/vnd.dlna.adts"] = ".adt",
            ["audio/wav"] = ".wav",
            ["audio/webm"] = ".weba",
            ["audio/x-aiff"] = ".aif",
            ["audio/x-mpegurl"] = ".m3u",
            ["audio/x-matroska"] = ".mka",
            ["audio/x-ms-wax"] = ".wax",
            ["audio/x-ms-wma"] = ".wma",
            ["drawing/x-dwf"] = ".dwf",
            ["font/collection"] = ".ttc",
            ["font/otf"] = ".otf",
            ["font/ttf"] = ".ttf",
            ["font/woff"] = ".woff",
            ["font/woff2"] = ".woff2",
            ["image/apng"] = ".apng",
            ["image/avif"] = ".avif",
            ["image/bmp"] = ".bmp",
            ["image/gif"] = ".gif",
            ["image/heic"] = ".heic",
            ["image/heif"] = ".heif",
            ["image/ief"] = ".ief",
            ["image/jpeg"] = ".jpg",
            ["image/jxl"] = ".jxl",
            ["image/png"] = ".png",
            ["image/svg+xml"] = ".svg",
            ["image/tiff"] = ".tif",
            ["image/vnd.microsoft.icon"] = ".ico",
            ["image/vnd.wap.wbmp"] = ".wbmp",
            ["image/webp"] = ".webp",
            ["image/x-cmu-raster"] = ".ras",
            ["image/x-cmx"] = ".cmx",
            ["image/x-icon"] = ".ico",
            ["image/x-portable-anymap"] = ".pnm",
            ["image/x-portable-bitmap"] = ".pbm",
            ["image/x-portable-graymap"] = ".pgm",
            ["image/x-portable-pixmap"] = ".ppm",
            ["image/x-rgb"] = ".rgb",
            ["image/x-xbitmap"] = ".xbm",
            ["image/x-xpixmap"] = ".xpm",
            ["image/x-xwindowdump"] = ".xwd",
            ["message/rfc822"] = ".eml",
            ["model/gltf+json"] = ".gltf",
            ["model/gltf-binary"] = ".glb",
            ["model/stl"] = ".stl",
            ["text/cache-manifest"] = ".appcache",
            ["text/calendar"] = ".ics",
            ["text/css"] = ".css",
            ["text/csv"] = ".csv",
            ["text/html"] = ".html",
            ["text/javascript"] = ".js",
            ["text/jsx"] = ".jsx",
            ["text/markdown"] = ".md",
            ["text/mdx"] = ".mdx",
            ["text/plain"] = ".txt",
            ["text/richtext"] = ".rtx",
            ["text/scriptlet"] = ".sct",
            ["text/sgml"] = ".sgml",
            ["text/svelte"] = ".svelte",
            ["text/tab-separated-values"] = ".tsv",
            ["text/tsx"] = ".tsx",
            ["text/typescript"] = ".ts",
            ["text/vbscript"] = ".vbs",
            ["text/vcard"] = ".vcf",
            ["text/vnd.sylk"] = ".sylk",
            ["text/vtt"] = ".vtt",
            ["text/x-vcalendar"] = ".vcs",
            ["text/vue"] = ".vue",
            ["text/x-component"] = ".htc",
            ["text/x-csharp"] = ".cs",
            ["text/x-dart"] = ".dart",
            ["text/x-go"] = ".go",
            ["text/x-java-source"] = ".java",
            ["text/x-kotlin"] = ".kt",
            ["text/x-less"] = ".less",
            ["text/xml"] = ".xml",
            ["text/x-ms-odc"] = ".odc",
            ["text/yaml"] = ".yaml",
            ["text/x-perl"] = ".pl",
            ["text/x-protobuf"] = ".proto",
            ["text/x-python"] = ".py",
            ["text/x-rust"] = ".rs",
            ["text/x-sass"] = ".sass",
            ["text/x-scss"] = ".scss",
            ["text/x-setext"] = ".etx",
            ["text/x-swift"] = ".swift",
            ["video/3gpp"] = ".3gp",
            ["video/3gpp2"] = ".3g2",
            ["video/mp2t"] = ".mts",
            ["video/mp4"] = ".mp4",
            ["video/mpeg"] = ".mpeg",
            ["video/ogg"] = ".ogv",
            ["video/quicktime"] = ".mov",
            ["video/vnd.dlna.mpeg-tts"] = ".tts",
            ["video/webm"] = ".webm",
            ["video/x-flv"] = ".flv",
            ["video/x-ivf"] = ".ivf",
            ["video/x-la-asf"] = ".lsf",
            ["video/x-matroska"] = ".mkv",
            ["video/x-ms-asf"] = ".asf",
            ["video/x-ms-dvr"] = ".dvr-ms",
            ["video/x-msvideo"] = ".avi",
            ["video/x-ms-wm"] = ".wm",
            ["video/x-ms-wmp"] = ".wmp",
            ["video/x-ms-wmv"] = ".wmv",
            ["video/x-ms-wmx"] = ".wmx",
            ["video/x-ms-wtv"] = ".wtv",
            ["video/x-ms-wvx"] = ".wvx",
            ["video/x-sgi-movie"] = ".movie",
        }.GetAlternateLookup<ReadOnlySpan<char>>();

#if DEBUG
        static MediaTypeMap()
        {
            // Validate dictionary consistency.

            int longestExtensionLength = 0;

            Debug.Assert(ExtensionToMediaTypeCount == s_extensionToMediaType.Dictionary.Count,
                $"Expected {ExtensionToMediaTypeCount} entries in {nameof(s_extensionToMediaType)}, but found {s_extensionToMediaType.Dictionary.Count}.");
            foreach (KeyValuePair<string, string> entry in s_extensionToMediaType.Dictionary)
            {
                Debug.Assert(
                    s_mediaTypeToExtension.ContainsKey(entry.Value),
                    $"Missing '{entry.Value}' in {nameof(s_mediaTypeToExtension)}");

                longestExtensionLength = Math.Max(longestExtensionLength, entry.Key.Length);
            }

            Debug.Assert(MediaTypeToExtensionCount == s_mediaTypeToExtension.Dictionary.Count,
                $"Expected {MediaTypeToExtensionCount} entries in {nameof(s_mediaTypeToExtension)}, but found {s_mediaTypeToExtension.Dictionary.Count}.");
            foreach (KeyValuePair<string, string> entry in s_mediaTypeToExtension.Dictionary)
            {
                Debug.Assert(
                    s_extensionToMediaType.ContainsKey(entry.Value),
                    $"Missing '{entry.Value}' in {nameof(s_extensionToMediaType)}");

                longestExtensionLength = Math.Max(longestExtensionLength, entry.Value.Length);
            }

            Debug.Assert(longestExtensionLength == MaxExtensionLength,
                $"Expected {MaxExtensionLength} as longest extension length, but found {longestExtensionLength}.");
        }
#endif

        /// <summary>
        /// Gets the media type (MIME type) for the specified file path or extension.
        /// </summary>
        /// <param name="pathOrExtension">A file path or extension (with or without leading period).</param>
        /// <returns>The media type associated with the extension, or <see langword="null"/> if no mapping exists.</returns>
        /// <remarks>
        /// <para>
        /// Some file extensions may map to multiple media types. In such cases, this method returns one of the possible media types.
        /// </para>
        /// <para>
        /// The method extracts the extension from <paramref name="pathOrExtension"/> using the same logic as <see cref="Path.GetExtension(string)"/>.
        /// If the input is already an extension (e.g. ".pdf" or "pdf"), it will be used directly.
        /// The comparison is case-insensitive.
        /// </para>
        /// </remarks>
        /// <exception cref="ArgumentNullException"><paramref name="pathOrExtension"/> is <see langword="null"/>.</exception>
        public static string? GetMediaType(string pathOrExtension)
        {
            ArgumentNullException.ThrowIfNull(pathOrExtension);
            return GetMediaType(pathOrExtension.AsSpan());
        }

        /// <summary>
        /// Gets the media type (MIME type) for the specified file path or extension.
        /// </summary>
        /// <param name="pathOrExtension">A file path or extension (with or without leading period).</param>
        /// <returns>The media type associated with the extension, or <see langword="null"/> if no mapping exists.</returns>
        /// <remarks>
        /// <para>
        /// Some file extensions may map to multiple media types. In such cases, this method returns one of the possible media types.
        /// </para>
        /// <para>
        /// The method extracts the extension from <paramref name="pathOrExtension"/> using the same logic as <see cref="Path.GetExtension(ReadOnlySpan{char})"/>.
        /// If the input is already an extension (e.g. ".pdf" or "pdf"), it will be used directly.
        /// The comparison is case-insensitive.
        /// </para>
        /// </remarks>
        public static string? GetMediaType(ReadOnlySpan<char> pathOrExtension)
        {
            scoped ReadOnlySpan<char> extension = Path.GetExtension(pathOrExtension);

            if (extension.IsEmpty)
            {
                // We couldn't extract an extension, so try using the full input.
                // If it doesn't start with a period, add one. If it's too long, just use as-is,
                // as it'll fail the lookup anyway.
                extension = pathOrExtension;
                if (!extension.IsEmpty && extension[0] != '.' && extension.Length < MaxExtensionLength)
                {
                    Span<char> buffer = stackalloc char[1 + extension.Length];
                    buffer.TryWrite($".{extension}", out _);
                    extension = buffer;
                }
            }

            s_extensionToMediaType.TryGetValue(extension, out string? result);
            return result;
        }

        /// <summary>
        /// Gets the file extension for the specified media type (MIME type).
        /// </summary>
        /// <param name="mediaType">The media type (e.g. "application/pdf").</param>
        /// <returns>The file extension (with leading period) associated with the media type, or <see langword="null"/> if no mapping exists.</returns>
        /// <remarks>
        /// <para>
        /// Some media types may map to multiple file extensions. In such cases, this method returns one of the possible file extensions.
        /// </para>
        /// <para>
        /// The comparison is case-insensitive. Parameters in the media type (e.g. "text/html; charset=utf-8") are ignored.
        /// </para>
        /// </remarks>
        /// <exception cref="ArgumentNullException"><paramref name="mediaType"/> is <see langword="null"/>.</exception>
        public static string? GetExtension(string mediaType)
        {
            ArgumentNullException.ThrowIfNull(mediaType);
            return GetExtension(mediaType.AsSpan());
        }

        /// <summary>
        /// Gets the file extension for the specified media type (MIME type).
        /// </summary>
        /// <param name="mediaType">The media type (e.g. "application/pdf").</param>
        /// <returns>The file extension (with leading period) associated with the media type, or <see langword="null"/> if no mapping exists.</returns>
        /// <remarks>
        /// <para>
        /// Some media types may map to multiple file extensions. In such cases, this method returns one of the possible file extensions.
        /// </para>
        /// <para>
        /// The comparison is case-insensitive. Parameters in the media type (e.g. "text/html; charset=utf-8") are ignored.
        /// </para>
        /// </remarks>
        public static string? GetExtension(ReadOnlySpan<char> mediaType)
        {
            int pos = mediaType.IndexOf(';');
            if (pos >= 0)
            {
                mediaType = mediaType.Slice(0, pos);
            }

            s_mediaTypeToExtension.TryGetValue(mediaType.Trim(), out string? value);
            return value;
        }
    }
}
